package com.reformer.commons.builder;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 全局序列号生成
 * yyyyMMddHHmmssSSS + ip最后三位+6位自增的序列号
 */
public class SerialNoBuilder {

    private static final String DATE_FORMAT = "yyyyMMddHHmmssSSS";

    private static final Integer DEFAULT_SEQUENCE_LENGTH = 6;

    private static final DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);

    private static final NumberFormat numberFormat = NumberFormat.getInstance();
    private static String serverId;

    static {
        numberFormat.setGroupingUsed(false);
        numberFormat.setMaximumIntegerDigits(DEFAULT_SEQUENCE_LENGTH);
        numberFormat.setMinimumIntegerDigits(DEFAULT_SEQUENCE_LENGTH);

        if (Strings.isNullOrEmpty(serverId)) {
            try {
                InetAddress address = InetAddress.getLocalHost();
                serverId = String.valueOf(address.getAddress()[3]);
            } catch (final UnknownHostException e) {
                throw new IllegalStateException("Cannot get LocalHost InetAddress, please check your network!", e);
            }
        }
    }

    private Lock lock = new ReentrantLock();
    private int bizNo = 1;
    private long lastTime;

    public static void setServerId(String serverId) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(serverId));
        SerialNoBuilder.serverId = serverId;
    }

    public String serializeNumInOneSecond() {
        return numberFormat.format(bizNo);
    }

    public String format(Object date) {
        return dateFormat.format(date);
    }

    public String getSerialNo() {
        try {
            lock.lock();
            long time = System.currentTimeMillis();
            if (lastTime == time) {
                ++bizNo;
            } else {
                bizNo = 1;
            }
            lastTime = time;
            return format(time) + serverId + serializeNumInOneSecond();
        } finally {
            lock.unlock();
        }

    }
}
